// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details	
		
module led_control
#(parameter DBGFPGAREV = 8'h01, DBGFPGATEST = 8'h00)
(
 // ------------------------
 // Clock and Reset signals
 // ------------------------
 input                    iClk,                                        //clock for sequential logic 
 input                    iRst_n,                                      //reset signal from PLL Lock, resets state machine to initial state
 // ----------------------------
 // inputs and outputs
 // ---------------------------- 
 input [7:0]              iCPUFPGAREV,                                 //CPU FPGA version, from CPU FPGA thru sGPIO
 input [7:0]              iCPUFPGATEST,                                //CPU FPGA test version, from CPU FPGA thru sGPIO
 input [7:0]              iSCMFPGAREV,                                 //SCM FPGA version, from CPU FPGA thru sGPIO
 input [7:0]              iSCMFPGATEST,                                //SCM FPGA test version, from CPU FPGA thru sGPIO
 
 input                    iENA,                                        //Enable signal, used to run at slower freq
 
 input                    iRST_PLTRST_CPU0_PLD_R_N,                    //PLTRST_N signal from CPU FPGA thru sGPIO (used to automatically switch from FPGA to BIOS postcodes in displays)
 
 input [7:0]              iSTATUS_LED,                                 //input to be reflected at status LEDs from sGPIO when oStatusLedSel is asserted
 output reg               oSTATUS_LED_SEL,                             //output generated by this module to select when STATUS LEDs should take into account the LED_CONTROL output pins
 
 input [7:0]              iFPGA_POST_CODE1,                            //Main Fpga postcode for 7-segment display 1 (MSB) before PLT_RST_N is deasserted (already encoded into 7-Seg Display)
 input [7:0]              iFPGA_POST_CODE2,                            //Main Fpga postcode for 7-segment display 2 (LSB) before PLT_RST_N is deasserted (already encoded into 7-Seg Display)
 input [7:0]              iBIOS_POST_CODE,                             //Port 80 post-codes from BIOS for the 2 7-Segment displays, after PLT_RST_N is deasserted
 input [7:0]              iPFR_POST_CODE,                              //PFR postcode to be displayed on 7-segment display 1 (MSB), by asserting PFR override signal (overriding Fpga & BIOS post-codes)
 input                    iPFR_OVERRIDE_N,                             //PRF override signal, comming from CPU FPGA thru sGPIO, if asserted, PRF postcode data is displayed in 7-segment displays, otherwise, FPGA or BIOS postcodes will be displayed depending on RST_PLTRST_N signal
 output reg               oPOST_CODE_SEL1_N,                           //to latch LED_CONTROL outputs into the 7-segment display1 (MSB) (active low)
 output reg               oPOST_CODE_SEL2_N,                           //to latch LED_CONTROL outputs into the 7-segment display2 (LSB) (active low)
 
 input [7:0]              iLED_CPU0_DIMM_CH1_8_FLT,                    //input for the Cpu0 Dimms 1(for 1DPC) CH 1-8 Fault LEDs indications
 output reg               oLED_CPU0_DIMM_CH1_8_FLT_SEL,                //to latch LED_CONTROL output into CPU0 Dimms 1(for 1DPC) CH 1-8 Fault LEDs
 
 input [3:0]              iLED_CPU0_DIMM_CH9_12_FLT,                   //input for the Cpu0 Dimms 1(for 1DPC) CH 9_12 Fault LEDs indications, only 4 channels valid
 output reg               oLED_CPU0_DIMM_CH9_12_FLT_SEL,               //to latch LED_CONTROL output into CPU0 Dimms 1(for 1DPC) CH 9_12 Fault LEDs
 
 input [7:0]              iLED_CPU1_DIMM_CH1_8_FLT,                    //input for the Cpu1 Dimms 1(for 1DPC) CH 1-8 Fault LEDs indications
 output reg               oLED_CPU1_DIMM_CH1_8_FLT_SEL,                //to latch LED_CONTROL output into CPU0 Dimms 1(for 1DPC) CH 1-8 Fault LEDs
 
 input [3:0]              iLED_CPU1_DIMM_CH9_12_FLT,                   //input for the Cpu1 Dimms 1(for 1DPC) CH 9_12 Fault LEDs indications, only 4 channels valid
 output reg               oLED_CPU1_DIMM_CH9_12_FLT_SEL,               //to latch LED_CONTROL output into CPU0 Dimms 1(for 1DPC) CH 9_12 Fault LEDs
 
 input                    iPLD_REV_N,                                  //when asserted (active low) will show CPU/SCM/Debug FPGA versions in 7-Segment Displays 2&1
 
 output [7:0]             oLED_CONTROL                                 //output of the mux to all LEDs resources
 
 );
   
//////////////////////////////////////////////////////////////////////////////////
// States for FSM
//////////////////////////////////////////////////////////////////////////////////
	localparam ST_INIT               = 4'd0;
	localparam ST_DISPLAY1           = 4'd1;
	localparam ST_DISPLAY1_D	      = 4'd2;
	localparam ST_DISPLAY2           = 4'd3;
	localparam ST_DISPLAY2_D         = 4'd4;
	localparam ST_STATUSLEDS         = 4'd5;
	localparam ST_CPU0_DIMM_LED_1_8  = 4'd6;
	localparam ST_CPU0_DIMM_LED_9_12 = 4'd7;
	localparam ST_CPU1_DIMM_LED_1_8  = 4'd8;
	
	localparam ENDVERCNT             = 9'd299;


//////////////////////////////////////////////////////////////////////////////////
// Parameters
//////////////////////////////////////////////////////////////////////////////////
	localparam  LOW =1'b0;
	localparam  HIGH=1'b1;

//////////////////////////////////////////////////////////////////////////////////
// Internal Signals
//////////////////////////////////////////////////////////////////////////////////
	reg [3:0]	rstate;
	reg [7:0]   rLED_CONTROL;                 //to register LED_CONTROL before output
	reg [2:0]   rVER_FLAG;                    //when PLD_REV_N button is pressed, this signal will toggle evey 1 sec to switch from CPU/SCM/DBG FPGA versions
   reg [8:0]	rVER_CNT;                     //from the 3.33 msec clock we will cnt to get a 1 second delay to toggle rVER_FLAG, so we can mux the CPU/SCM/DBG FPGA versions displayed while PLD_REV_N is asserted

//////////////////////////////////////////////////////////////////////////////////
// Combinational logic
//////////////////////////////////////////////////////////////////////////////////	
	assign      oLED_CONTROL         = rLED_CONTROL;
	
//////////////////////////////////////////////////////////////////////////////////
// Local function to decode from Hex to 7-Segment Display & LED
//////////////////////////////////////////////////////////////////////////////////
	
	function [7:0] fDecoder;
      input [6:0] iEncodedData;       //data to be decoded into BCD 7-segments for displays
      input       iDotSel;            //it indicates if we need to turn the displays dots or not (depending if it is data for MainFpga (0), BIOS (1), or PFR (2)
      
      begin
		 case (iEncodedData)            //Decoder from decimal to 7 Seg
		   7'd0:  fDecoder[6:0] = 7'b1000000; //0 -- 40h
		   7'd1:  fDecoder[6:0] = 7'b1111001; //1 -- 79h
		   7'd2:  fDecoder[6:0] = 7'b0100100; //2 -- 24h
		   7'd3:  fDecoder[6:0] = 7'b0110000; //3 -- 30h
		   7'd4:  fDecoder[6:0] = 7'b0011001; //4 -- 19h
		   7'd5:  fDecoder[6:0] = 7'b0010010; //5 -- 12h
		   7'd6:  fDecoder[6:0] = 7'b0000010; //6 -- 02h
		   7'd7:  fDecoder[6:0] = 7'b1111000; //7 -- 78h
		   7'd8:  fDecoder[6:0] = 7'b0000000; //8 -- 00h
		   7'd9:  fDecoder[6:0] = 7'b0010000; //9 -- 10h
		   7'd10: fDecoder[6:0] = 7'b0001000; //A -- 08h
		   7'd11: fDecoder[6:0] = 7'b0000011; //b -- 03h
		   7'd12: fDecoder[6:0] = 7'b1000110; //C -- 46h
		   7'd13: fDecoder[6:0] = 7'b0100001; //d -- 21h
		   7'd14: fDecoder[6:0] = 7'b0000110; //E -- 06h
		   7'd15: fDecoder[6:0] = 7'b0001110; //F -- 0Eh
		   7'd16: fDecoder[6:0] = 7'b0111111; //- -- 3Fh
		   default: 
			 fDecoder[6:0] = 7'b1111111; //ALL OFF
         endcase // case (encoded_data)

         fDecoder[7] = iDotSel;
      end
   endfunction // decoder
	
//////////////////////////////////////////////////////////////////////////////////
// FSM for LED control logic
//////////////////////////////////////////////////////////////////////////////////

   always @(posedge iClk or negedge iRst_n) begin
      if(!iRst_n) begin
		   rstate                        <= ST_INIT;
			
			oSTATUS_LED_SEL               <= LOW;
			oPOST_CODE_SEL1_N             <= HIGH;
			oPOST_CODE_SEL2_N             <= HIGH;
			oLED_CPU0_DIMM_CH1_8_FLT_SEL  <= LOW;
			oLED_CPU0_DIMM_CH9_12_FLT_SEL <= LOW;
			oLED_CPU1_DIMM_CH1_8_FLT_SEL  <= LOW;
			oLED_CPU1_DIMM_CH9_12_FLT_SEL <= LOW;
			
			rVER_FLAG                     <= 3'b000;
			rVER_CNT                      <= 9'd0;
			
			rLED_CONTROL                  <= 8'hFF;
		end
		
		else begin
		   if(iENA) begin
			   if(!iPLD_REV_N) begin                  //When assert, toggle per 1-sec to show three FPGA's version
				   if(rVER_CNT == ENDVERCNT) begin
					   rVER_CNT             <= 9'd0;
						
						if(rVER_FLAG == 3'b110) begin
					      rVER_FLAG         <= 3'b000;
						end
						
						else begin
						   rVER_FLAG         <= rVER_FLAG + 1'b1;
						end						
					end //if(rVER_CNT == ENDVERCNT)
					
				   else begin
				      rVER_CNT             <= rVER_CNT + 1'b1;
				   end
					
				end //if(!iPLD_REV_N)

				else begin
				   rVER_FLAG               <= 3'b000;
					rVER_CNT                <= 9'd0;
				end
				
				case(rstate)
				   ST_INIT: begin
			         oSTATUS_LED_SEL               <= LOW;
			         oPOST_CODE_SEL1_N             <= LOW;         //enabling data to be in 7-Seg Display1 (MSB)
			         oPOST_CODE_SEL2_N             <= HIGH;
			         oLED_CPU0_DIMM_CH1_8_FLT_SEL  <= LOW;
			         oLED_CPU0_DIMM_CH9_12_FLT_SEL <= LOW;
			         oLED_CPU1_DIMM_CH1_8_FLT_SEL  <= LOW;
			         oLED_CPU1_DIMM_CH9_12_FLT_SEL <= LOW;
						
						rstate                        <= ST_DISPLAY1;
						
						if(!iPLD_REV_N) begin
						   case(rVER_FLAG) 
							   3'b000 : rLED_CONTROL   <= fDecoder({3'h0,iCPUFPGAREV[7:4]},0);              //if PldRev_n button is pushed, it shows CPU Fpga versions (middle dot ON)
								3'b001 : rLED_CONTROL   <= fDecoder({3'h0,iCPUFPGATEST[7:4]},0);             //if PldRev_n button is pushed, it shows CPU Fpga versions (middle dot ON)
								3'b010 : rLED_CONTROL   <= fDecoder({3'h0,iSCMFPGAREV[7:4]},0);              //if PldRev_n button is pushed, it shows SCM Fpga versions (middle dot ON)
								3'b011 : rLED_CONTROL   <= fDecoder({3'h0,iSCMFPGATEST[7:4]},0);             //if PldRev_n button is pushed, it shows SCM Fpga versions (middle dot ON)
								3'b100 : rLED_CONTROL   <= fDecoder({3'h0,DBGFPGAREV[7:4]},1);               //if PldRev_n button is pushed, it shows DBG Fpga versions (middle dot OFF)
								3'b101 : rLED_CONTROL   <= fDecoder({3'h0,DBGFPGATEST[7:4]},1);              //if PldRev_n button is pushed, it shows DBG Fpga versions (middle dot OFF)
								3'b110 : rLED_CONTROL   <= fDecoder(7'b1111111,0);                           //if PldRev_n button is pushed, it shows ".." to let user know it has finished a display round
								default: rLED_CONTROL   <= fDecoder({3'h0,iCPUFPGAREV[7:4]},0);
							endcase //case(rVER_FLAG)
						end //if(!iPLD_REV_N)
						
						else begin
						   if(!iPFR_OVERRIDE_N) begin                //if PFR_OVERRIDE_N is asserted, select PFR postcodes over platform FPGA or BIOS
							   rLED_CONTROL            <= fDecoder({3'h0,iPFR_POST_CODE[7:4]},1);           //PFR postcode, 1 dot, middle dot OFF
							end //if(!iPFR_OVERRIDE_N)
							
							else begin
							   if(!iRST_PLTRST_CPU0_PLD_R_N) begin    //with no PFR override and before system out of reset, show platform FPGA postcode, 2 dots
								   rLED_CONTROL         <= iFPGA_POST_CODE1;                                 //platform FPGA postcode, middle dot ON
								end //if(!iRST_PLTRST_CPU0_PLD_R_N)
								
								else begin                            //BIOS postcode after system out of reset, no dot
								   rLED_CONTROL         <= fDecoder({3'h0,iBIOS_POST_CODE[7:4]},1);          //middle dot OFF
								end
							end
						end
					end //case ST_INIT
					
					ST_DISPLAY1: begin
					   rstate                        <= ST_DISPLAY1_D;                                    //Keep one more cycle for ST_DISPLAY1
					end //case ST_DISPLAY1
					
					ST_DISPLAY1_D: begin
					   oSTATUS_LED_SEL               <= LOW;
			         oPOST_CODE_SEL1_N             <= HIGH;      //disabling data to be in 7-Seg Display1 (MSB)         
			         oPOST_CODE_SEL2_N             <= LOW;       //enabling data to be in 7-Seg Display2 (LSB)
			         oLED_CPU0_DIMM_CH1_8_FLT_SEL  <= LOW;
			         oLED_CPU0_DIMM_CH9_12_FLT_SEL <= LOW;
			         oLED_CPU1_DIMM_CH1_8_FLT_SEL  <= LOW;
			         oLED_CPU1_DIMM_CH9_12_FLT_SEL <= LOW;
						
						rstate                        <= ST_DISPLAY2;
						
						if(!iPLD_REV_N) begin
						   case(rVER_FLAG) 
							   3'b000 : rLED_CONTROL   <= fDecoder({3'h0,iCPUFPGAREV[3:0]},0);              //if PldRev_n button is pushed, it shows CPU Fpga versions (end dot ON)
								3'b001 : rLED_CONTROL   <= fDecoder({3'h0,iCPUFPGATEST[3:0]},0);             //if PldRev_n button is pushed, it shows CPU Fpga versions (end dot ON)
								3'b010 : rLED_CONTROL   <= fDecoder({3'h0,iSCMFPGAREV[3:0]},1);              //if PldRev_n button is pushed, it shows SCM Fpga versions (end dot OFF)
								3'b011 : rLED_CONTROL   <= fDecoder({3'h0,iSCMFPGATEST[3:0]},1);             //if PldRev_n button is pushed, it shows SCM Fpga versions (end dot OFF)
								3'b100 : rLED_CONTROL   <= fDecoder({3'h0,DBGFPGAREV[3:0]},1);               //if PldRev_n button is pushed, it shows DBG Fpga versions (end dot OFF)
								3'b101 : rLED_CONTROL   <= fDecoder({3'h0,DBGFPGATEST[3:0]},1);              //if PldRev_n button is pushed, it shows DBG Fpga versions (end dot OFF)
								3'b110 : rLED_CONTROL   <= fDecoder(7'b1111111,0);                           //if PldRev_n button is pushed, it shows ".." to let user know it has finished a display round
								default: rLED_CONTROL   <= fDecoder({3'h0,iCPUFPGAREV[3:0]},0);
							endcase //case(rVER_FLAG)
						end //if(!iPLD_REV_N)
						
						else begin
						   if(!iPFR_OVERRIDE_N) begin                //if PFR_OVERRIDE_N is asserted, select PFR postcodes over platform FPGA or BIOS
							   rLED_CONTROL            <= fDecoder({3'h0,iPFR_POST_CODE[3:0]},0);           //PFR postcode, 1 dot, end dot ON
							end //if(!iPFR_OVERRIDE_N)
							
							else begin
							   if(!iRST_PLTRST_CPU0_PLD_R_N) begin    //with no PFR override and before system out of reset, show platform FPGA postcode, 2 dots
								   rLED_CONTROL         <= iFPGA_POST_CODE2;                                 //platform FPGA postcode, end dot ON
								end //if(!iRST_PLTRST_CPU0_PLD_R_N)
								
								else begin                            //BIOS postcode after system out of reset, no dot
								   rLED_CONTROL         <= fDecoder({3'h0,iBIOS_POST_CODE[3:0]},1);          //end dot OFF
								end
							end
						end
					end //case ST_DISPLAY1_D
					
					ST_DISPLAY2: begin
					   rstate                        <= ST_DISPLAY2_D;                                    //Keep one more cycle for ST_DISPLAY2
					end //case ST_DISPLAY2
					
					ST_DISPLAY2_D: begin
					   oSTATUS_LED_SEL               <= HIGH;        //enabling STATUS_LED display
			         oPOST_CODE_SEL1_N             <= HIGH;        //disabling data to be in 7-Seg Display1 (MSB)         
			         oPOST_CODE_SEL2_N             <= HIGH;        //disabling data to be in 7-Seg Display2 (LSB)
			         oLED_CPU0_DIMM_CH1_8_FLT_SEL  <= LOW;      
			         oLED_CPU0_DIMM_CH9_12_FLT_SEL <= LOW;
			         oLED_CPU1_DIMM_CH1_8_FLT_SEL  <= LOW;
			         oLED_CPU1_DIMM_CH9_12_FLT_SEL <= LOW;
						
						rstate                        <= ST_STATUSLEDS;
						
						rLED_CONTROL                  <= iSTATUS_LED; //data coming from sGPIO for Status LEDs
					end //case ST_DISPLAY2_D
					
					ST_STATUSLEDS: begin
					   oSTATUS_LED_SEL               <= LOW;         //disabling STATUS_LED display
			         oPOST_CODE_SEL1_N             <= HIGH;        //disabling data to be in 7-Seg Display1 (MSB)         
			         oPOST_CODE_SEL2_N             <= HIGH;        //disabling data to be in 7-Seg Display2 (LSB)
			         oLED_CPU0_DIMM_CH1_8_FLT_SEL  <= HIGH;        //enabling CPU0 DIMM CH1-8 Fault LED display      
			         oLED_CPU0_DIMM_CH9_12_FLT_SEL <= LOW;
			         oLED_CPU1_DIMM_CH1_8_FLT_SEL  <= LOW;
			         oLED_CPU1_DIMM_CH9_12_FLT_SEL <= LOW;
						
						rstate                        <= ST_CPU0_DIMM_LED_1_8;
						
						rLED_CONTROL                  <= iLED_CPU0_DIMM_CH1_8_FLT;     //data coming from BMC sGPIO for CPU0 DIMM1 Fault indications 
					end //case ST_STATUSLEDS
					
					ST_CPU0_DIMM_LED_1_8: begin
					   oSTATUS_LED_SEL               <= LOW;         //disabling STATUS_LED display
			         oPOST_CODE_SEL1_N             <= HIGH;        //disabling data to be in 7-Seg Display1 (MSB)         
			         oPOST_CODE_SEL2_N             <= HIGH;        //disabling data to be in 7-Seg Display2 (LSB)
			         oLED_CPU0_DIMM_CH1_8_FLT_SEL  <= LOW;         //disabling CPU0 DIMM CH1-8 Fault LED display      
			         oLED_CPU0_DIMM_CH9_12_FLT_SEL <= HIGH;        //enabling CPU0 DIMM CH9-12 Fault LED display
			         oLED_CPU1_DIMM_CH1_8_FLT_SEL  <= LOW;
			         oLED_CPU1_DIMM_CH9_12_FLT_SEL <= LOW;
						
						rstate                        <= ST_CPU0_DIMM_LED_9_12;
						
						rLED_CONTROL                  <= {4'b0000, iLED_CPU0_DIMM_CH9_12_FLT};     //only 4 bits are valid, data coming from BMC sGPIO for CPU0 DIMM1 Fault indications
					end //case ST_CPU0_DIMM_LED_1_8
					
					ST_CPU0_DIMM_LED_9_12: begin
					   oSTATUS_LED_SEL               <= LOW;         //disabling STATUS_LED display
			         oPOST_CODE_SEL1_N             <= HIGH;        //disabling data to be in 7-Seg Display1 (MSB)         
			         oPOST_CODE_SEL2_N             <= HIGH;        //disabling data to be in 7-Seg Display2 (LSB)
			         oLED_CPU0_DIMM_CH1_8_FLT_SEL  <= LOW;         //disabling CPU0 DIMM CH1-8 Fault LED display      
			         oLED_CPU0_DIMM_CH9_12_FLT_SEL <= LOW;         //disabling CPU0 DIMM CH9-12 Fault LED display
			         oLED_CPU1_DIMM_CH1_8_FLT_SEL  <= HIGH;        //enabling CPU1 DIMM CH1-8 Fault LED display
			         oLED_CPU1_DIMM_CH9_12_FLT_SEL <= LOW;
						
						rstate                        <= ST_CPU1_DIMM_LED_1_8;
						
						rLED_CONTROL                  <= iLED_CPU1_DIMM_CH1_8_FLT;     //data coming from BMC sGPIO for CPU0 DIMM1 Fault indications
					end //case ST_CPU0_DIMM_LED_9_12
					
					ST_CPU1_DIMM_LED_1_8: begin
					   oSTATUS_LED_SEL               <= LOW;         //disabling STATUS_LED display
			         oPOST_CODE_SEL1_N             <= HIGH;        //disabling data to be in 7-Seg Display1 (MSB)         
			         oPOST_CODE_SEL2_N             <= HIGH;        //disabling data to be in 7-Seg Display2 (LSB)
			         oLED_CPU0_DIMM_CH1_8_FLT_SEL  <= LOW;         //disabling CPU0 DIMM CH1-8 Fault LED display      
			         oLED_CPU0_DIMM_CH9_12_FLT_SEL <= LOW;         //disabling CPU0 DIMM CH9-12 Fault LED display
			         oLED_CPU1_DIMM_CH1_8_FLT_SEL  <= LOW;         //disabling CPU1 DIMM CH1-8 Fault LED display
			         oLED_CPU1_DIMM_CH9_12_FLT_SEL <= HIGH;        //enabling CPU1 DIMM CH9-12 Fault LED display
						
						rstate                        <= ST_INIT;
						
						rLED_CONTROL                  <= {4'b0000, iLED_CPU1_DIMM_CH9_12_FLT};     //only 4 bits are valid, data coming from BMC sGPIO for CPU1 DIMM1 Fault indications
					end //case ST_CPU1_DIMM_LED_1_8
					
					default: begin
					   rstate                        <= ST_INIT;
					end //case default
				endcase
				
			end //if(iENA)
			
			else begin
			   rstate                              <= rstate;
			end
		end
   end	
	
endmodule
